﻿using Basic.EventBus.Eventbus;
using Basic.EventBus.EventBusKafka;
using Basic.EventBus.EventBusRabbitMQ;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;

namespace Basic.EventBus.Extensions
{
    public static class EventBusExtension
    {
        public static IBusBrokerConfig GetConfig(IConfigurationSection rabitmqSection)
        {
            var brokerType = rabitmqSection.GetSection(nameof(IBusBrokerConfig.BrokerType)).Get<string>();
            if (string.Equals("Kafka", brokerType))
                return rabitmqSection.Get<KafkaBusBrokerConfig>();

            return rabitmqSection.Get<RabbitMQBusBrokerConfig>();
        }

        public static string GetGenericTypeName(this Type type)
        {
            var typeName = string.Empty;

            if (type.IsGenericType)
            {
                var genericTypes = string.Join(",", type.GetGenericArguments().Select(t => t.Name).ToArray());
                typeName = $"{type.Name.Remove(type.Name.IndexOf('`'))}<{genericTypes}>";
            }
            else
            {
                typeName = type.Name;
            }
            return typeName;
        }

        public static string GetGenericTypeName(this object @object)
        {
            return @object.GetType().GetGenericTypeName();
        }

        public static IServiceCollection AddEventBus(this IServiceCollection services, IConfigurationSection section)
        {
            var busConf = GetConfig(section);
            //services.RegisterSerialization(busConf.SerializerName);

            if (busConf is KafkaBusBrokerConfig kafkaConf)
            {
                services.AddSingleton(kafkaConf);
                services.AddSingleton<IEventPublisher, KafkaProducer>();
                services.AddSingleton<IEventSubscriber, KafkaSubscriber>();
            }
            else if (busConf is RabbitMQBusBrokerConfig rabbitMQConf)
            {
                services.AddSingleton(rabbitMQConf);
                services.AddSingleton<RabbitMQConnections>();
                services.AddSingleton<IEventPublisher, RabbitMQProducer>();
                services.AddSingleton<IEventSubscriber, RabbitMQSubscriber>();
            }
            return services;
        }

        public static IServiceCollection AddEventHandler(this IServiceCollection services, params Assembly[] assemblies)
        {
            List<Type> handlerTypes = new List<Type>(16);
            Type baseType = typeof(ISubscriberHandler);
            foreach (Assembly assembly in assemblies)
            {
                var publicTypes = assembly.GetExportedTypes().Where(s => s.IsAbstract == false);
                var subTypes = publicTypes.Where(s => s.GetInterfaces().Any(s => s.GUID == baseType.GUID)).ToList();
                handlerTypes.AddRange(subTypes);
            }

            foreach (var type in handlerTypes)
                services.AddSingleton(type);

            return services;
        }

    }
}